home *** CD-ROM | disk | FTP | other *** search
/ Chip 1997 December / CHIPNET Aralık 1997.iso / linux / redhat / misc / src / install / install2.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-11  |  26.8 KB  |  1,054 lines

  1. /*
  2.  * install2.c
  3.  * 
  4.  * This is the second half of the install. It is exec'd from the first half
  5.  * once the secondary media has been mounted. It does a bunch of argv
  6.  * processing to figure out what the first half did. It's a bit of a hack, but
  7.  * it gives us a nice install as far as the user can see.
  8.  *
  9.  * Erik Troan (ewt@redhat.com)
  10.  *
  11.  * Copyright 1997 Red Hat Software 
  12.  *
  13.  * This software may be freely redistributed under the terms of the GNU
  14.  * public license.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program; if not, write to the Free Software
  18.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  *
  20.  */
  21.  
  22. /*
  23.  * We assume the following:
  24.  *
  25.  *    /usr/bin -> any binaries we might need
  26.  *
  27.  * it's up to the first stage installer to make sure this happens.
  28.  *
  29.  */
  30.  
  31. #include <dirent.h>
  32. #include <errno.h>
  33. #include <fcntl.h>
  34. #include <newt.h>
  35. #include <stdlib.h>
  36. #include <string.h>
  37. #include <sys/stat.h>
  38. #include <sys/sysmacros.h>
  39. #include <sys/time.h>
  40. #include <sys/wait.h>
  41. #include <termios.h>
  42. #include <unistd.h>
  43.  
  44. #include "commands.h"
  45. #include "config.h"
  46. #include "devices.h"
  47. #include "doit.h"
  48. #include "fs.h"
  49. #include "hd.h"
  50. #include "install.h"
  51. #include "kbd.h"
  52. #include "kernel.h"
  53. #include "lilo.h"
  54. #include "log.h"
  55. #include "methods.h"
  56. #include "mkswap.h"
  57. #include "net.h"
  58. #include "perror.h"
  59. #include "pkgs.h"
  60. #include "printercfg.h"
  61. #include "run.h"
  62. #include "scsi.h"
  63. #include "upgrade.h"
  64. #include "windows.h"
  65.  
  66. int testing = 0;
  67.  
  68. #define STEP_FIRST    0
  69.  
  70. #define STEP_PATH        0
  71. #define STEP_SCSI        1
  72. #define STEP_FDISK        2
  73. #define STEP_SWAP        3
  74. #define STEP_FINDPKGS         4
  75. #define STEP_MTAB         5
  76. #define STEP_FORMAT         6
  77. #define STEP_PICKPKGS         7
  78. #define STEP_DOIT        8
  79. #define STEP_FINISHNET        9
  80. #define STEP_TIMECONFIG        10
  81. #define STEP_PRINTER        11
  82. #define STEP_ROOTPW        12
  83. #define STEP_LILO        13
  84.  
  85. #define STEP_UPG_SCSI        1
  86. #define STEP_UPG_PKGS        2
  87. #define STEP_UPG_MTAB        3
  88. #define STEP_UPG_FFILES        4
  89. #define STEP_UPG_DOIT        5
  90. #define STEP_UPG_FINISHNET    6
  91. #define STEP_UPG_LILO        7
  92.  
  93. #define STEP_DONE    1000
  94.  
  95. struct installState {
  96.     int isUpgrade, lastChoice;
  97.     char * pcmcia, * kernel, * keyboard;
  98.     struct partitionTable table;
  99.     struct fstab fstab;
  100.     struct pkgSet ps;
  101.     struct componentSet cs;
  102.     struct installMethod * method;
  103.     struct netInterface intf;
  104.     struct netConfig netc;
  105.     struct driversLoaded * dl;
  106.     struct installStep * steps;
  107. } ;
  108.  
  109. typedef int (*installStepFn)(struct installState * state);
  110.  
  111. static int setupSCSI(struct installState * state);
  112. static int partitionDisks(struct installState * state);
  113. static int setupSwap(struct installState * state);
  114. static int findInstallFiles(struct installState * state);
  115. static int setupFilesystem(struct installState * state);
  116. static int formatPartitions(struct installState * state);
  117. static int choosePackages(struct installState * state);
  118. static int doInstallStep(struct installState * state);
  119. static int setRootPassword(struct installState * state);
  120. static int configureTimezone(struct installState * state);
  121. static int configurePrinter(struct installState * state);
  122. static int setupBootloader(struct installState * state);
  123. static int finishNetworking(struct installState * state);
  124. static int selectPath(struct installState * state);
  125. static int upgrChoosePackages(struct installState * state);
  126. static int upgrFindInstall(struct installState * state);
  127. static void setupSerialConsole(void);
  128.  
  129. struct installStep {
  130.     char * name;
  131.     int prev, next;
  132.     installStepFn fn;
  133.     int skipOnCancel;
  134.     int completed;
  135. };
  136.  
  137. struct installStep installSteps[] = { 
  138.     { "Select installation path",    -1,        STEP_SCSI,
  139.     selectPath, 0, 0 },
  140.     { "Setup SCSI",             STEP_PATH,     STEP_FDISK,
  141.     setupSCSI, 0, 0 },
  142.     { "Partition disks",         STEP_PATH,     STEP_SWAP,
  143.     partitionDisks, 0, 0 },
  144.     { "Setup swap space",         STEP_FDISK,     STEP_FINDPKGS,
  145.     setupSwap, 0, 0 },
  146.     { "Find installation files",    STEP_SWAP,    STEP_MTAB,
  147.     findInstallFiles, 1, 0 },
  148.     { "Setup filesystems",        STEP_SWAP,    STEP_FORMAT,
  149.     setupFilesystem, 0, 0 },
  150.     { "Choose partitions to format",    STEP_MTAB,    STEP_PICKPKGS,
  151.     formatPartitions, 0, 0 },
  152.     { "Choose packages to install",    STEP_FORMAT,    STEP_DOIT,
  153.     choosePackages, 0, 0 },
  154.     { "Install system",            -1,        STEP_FINISHNET,
  155.     doInstallStep, 0, 0 },
  156.     { "Configure networking",        -1,        STEP_TIMECONFIG,
  157.     finishNetworking, 0, 0 },
  158.     { "Configure timezone",        STEP_FINISHNET,    STEP_PRINTER,
  159.     configureTimezone, 0, 0 },
  160.     { "Configure printer",        STEP_TIMECONFIG, STEP_ROOTPW,
  161.     configurePrinter, 0, 0 },
  162.     { "Set root password",        STEP_PRINTER,    STEP_LILO,
  163.     setRootPassword, 0, 0 },
  164.     { "Install bootloader",        STEP_ROOTPW,    STEP_DONE,
  165.     setupBootloader, 0, 0 },
  166. };
  167.  
  168. struct installStep upgradeSteps[] = { 
  169.     { "Select installation path",    -1,        STEP_UPG_SCSI,
  170.     selectPath, 0, 0 },
  171.     { "Setup SCSI",             STEP_PATH,     STEP_UPG_PKGS,
  172.     setupSCSI, 0, 0 },
  173.     { "Find installation files",    STEP_PATH,    STEP_UPG_MTAB,
  174.     findInstallFiles, 1, 0 },
  175.     { "Find current installation",    STEP_UPG_PKGS,    STEP_UPG_FFILES,
  176.     upgrFindInstall, 0, 0 },
  177.     { "Choose packages to upgrade",    STEP_UPG_FFILES,STEP_UPG_DOIT,
  178.     upgrChoosePackages, 0, 0 },
  179.     { "Upgrade system",            -1,        STEP_UPG_FINISHNET,
  180.     doInstallStep, 0, 0 },
  181.     { "Install bootloader",        STEP_UPG_FINISHNET,    STEP_DONE,
  182.     setupBootloader, 0, 0 },
  183. };
  184.  
  185. void spawnShell(void) {
  186.     pid_t pid;
  187.     int fd;
  188.  
  189.     if (!testing) {
  190.     fd = open("/dev/tty2", O_RDWR);
  191.     if (fd < 0) {
  192.         logMessage("cannot open /dev/tty2 -- no shell will be provided");
  193.         return;
  194.     } else if (access("/usr/bin/sh",  X_OK))  {
  195.         logMessage("cannot open shell - /usr/bin/sh doesn't exist");
  196.         return;
  197.     }
  198.  
  199.     if (!(pid = fork())) {
  200.         dup2(fd, 0);
  201.         dup2(fd, 1);
  202.         dup2(fd, 2);
  203.  
  204.         close(fd);
  205.         setsid();
  206.  
  207.         execl("/bin/sh", "-/bin/sh", NULL);
  208.         logMessage(perrorstr("exec of /bin/sh failed"));
  209.     }
  210.  
  211.     close(fd);
  212.     }
  213. }
  214.  
  215. static int setupSCSI(struct installState * state) {
  216.     return setupSCSIInterfaces(0, &state->dl);
  217. }
  218.  
  219. static int partitionDisks(struct installState * state) {
  220.     int rc;
  221.     
  222.     if (!state->isUpgrade) {
  223.     rc = partitionDrives();
  224.     if (rc) return rc;
  225.     }
  226.  
  227.     return findAllPartitions(&state->table);
  228. }
  229.  
  230. static int findInstallFiles(struct installState * state) {
  231.     int rc;
  232.  
  233.     if (!state->table.parts) { 
  234.     rc = findAllPartitions(&state->table);
  235.     if (rc) return rc;
  236.     }
  237.  
  238.     if (state->method->prepareRoot) {
  239.     rc = state->method->prepareRoot(state->method, state->table,
  240.                     &state->netc, &state->intf,
  241.                     &state->dl);
  242.     if (rc) return rc;
  243.     }
  244.  
  245.     if ((rc = state->method->getPackageSet(state->method, &state->ps)))
  246.     return rc;
  247.     if ((state->method->getComponentSet(state->method, &state->ps, 
  248.      &state->cs)) )
  249.     return rc;
  250.  
  251.     return 0;
  252. }
  253.  
  254. static int setupFilesystem(struct installState * state) {
  255.     return setupMountTable(state->table, &state->fstab, &state->intf,
  256.                &state->netc, &state->dl);
  257. }
  258.  
  259. static int formatPartitions(struct installState * state) {
  260.     return queryFormatFilesystems(&state->fstab);
  261. }
  262.  
  263. static int setupSwap(struct installState * state) {
  264.     return activeSwapSpace(&state->table, &state->fstab);
  265. }
  266.  
  267. static int choosePackages(struct installState * state) {
  268.     return psSelectPackages(&state->ps, &state->cs, 0, 0);
  269. }
  270.  
  271. static int doInstallStep(struct installState * state) {
  272.     int rc;
  273.     char * netSharedPath = NULL;
  274.     FILE * f;
  275.     int netSharedLength;
  276.     int i;
  277.  
  278.     if (!state->isUpgrade) {
  279.     winMessage(15, 7, 50, 10, "Install log", "A complete log "
  280.             "of your installation will be in /tmp/install.log "
  281.             "after rebooting your system. You may want to keep "
  282.             "this file for later reference.");
  283.  
  284.     rc = formatFilesystems(&state->fstab);
  285.     if (rc) return rc;
  286.  
  287.     rc = mountFilesystems(&state->fstab);
  288.     if (rc) return rc;
  289.  
  290.     if (state->method->prepareMedia) {
  291.         rc = state->method->prepareMedia(state->method, &state->fstab);
  292.         if (rc) {
  293.         umountFilesystems(&state->fstab);
  294.         return rc;
  295.         }
  296.     }
  297.     } else {
  298.     winMessage(15, 7, 50, 10, "Upgrade log", "A complete log "
  299.             "of your upgrade will be in /tmp/upgrade.log when "
  300.             "the upgrade is finished. After rebooting, please "
  301.             "read it to ensure configuration files are properly "
  302.             "updated.");
  303.     }
  304.  
  305.     /* FIXME: should this read the net shared path from /etc/rpmrc
  306.        during upgrades??? Probably. */
  307.     for (i = netSharedLength = 0; i < state->fstab.numEntries; i++) 
  308.     if (state->fstab.entries[i].type == PART_NFS)
  309.         netSharedLength += 1 + strlen(state->fstab.entries[i].mntpoint);
  310.  
  311.     if (netSharedLength) {
  312.     netSharedPath = alloca(netSharedLength);
  313.     *netSharedPath = '\0';
  314.     for (i = netSharedLength = 0; i < state->fstab.numEntries; i++) {
  315.         if (state->fstab.entries[i].type == PART_NFS) {
  316.         if (*netSharedPath) strcat(netSharedPath, ":");
  317.         strcat(netSharedPath, state->fstab.entries[i].mntpoint);
  318.         }
  319.         }
  320.  
  321.     logMessage("netSharedPath is: %s\n", netSharedPath);
  322.     }
  323.  
  324.     rc = doInstall(state->method, state->cs.preskel, &state->ps, 
  325.            netSharedPath, state->keyboard, state->isUpgrade);
  326.  
  327.     if (netSharedPath && access("/mnt/etc/rpmrc", X_OK)) {
  328.     logMessage("creating /etc/rpmrc for netshared info (as none exists)");
  329.     f = fopen("/mnt/etc/rpmrc", "w");
  330.     if (!f) {
  331.         errorWindow("error creating /mnt/etc/rpmrc: %s");
  332.     } else {
  333.         fprintf(f, "netsharedpath: %s\n", netSharedPath);
  334.         fclose(f);
  335.     }
  336.     }
  337.  
  338.     sync();
  339.     sync();
  340.  
  341.     if (!rc) psFreeComponentSet(&state->cs);
  342.  
  343.     configPCMCIA(state->pcmcia);
  344.  
  345.     return rc;
  346. }
  347.  
  348.  
  349. static char mksalt(int seed) {
  350.     int num = seed % 64;
  351.  
  352.     if (num < 26)
  353.     return 'a' + num;
  354.     else if (num < 52)
  355.     return 'A' + (num - 26);
  356.     else if (num < 62)
  357.     return '0' + (num - 52);
  358.     else if (num == 63)
  359.     return '.';
  360.     else
  361.     return '/';
  362. }
  363.  
  364. static int setRootPassword(struct installState * state) {
  365.     newtComponent form, text, pw1Entry, pw2Entry;
  366.     char * pw1, * pw2;
  367.     int done = 0;
  368.     char salt[3];
  369.     char cmd[200];
  370.     struct timeval time1, time2;
  371.     char * pw;
  372.  
  373.     gettimeofday(&time1, NULL);
  374.  
  375.     newtOpenWindow(15, 4, 50, 14, "Root Password");
  376.  
  377.     form = newtForm(NULL, NULL, 0);
  378.  
  379.     text = newtTextbox(1, 1, 47, 5, NEWT_TEXTBOX_WRAP);
  380.     newtTextboxSetText(text,
  381.     "Pick a root password. You must type it twice to ensure you know "
  382.     "what it is and didn't make a mistake in typing. Remember that the "
  383.     "root password is a critical part of system security!");
  384.  
  385.     newtFormAddComponent(form, newtLabel(3, 7, "Password        :"));
  386.     newtFormAddComponent(form, newtLabel(3, 8, "Password (again):"));
  387.  
  388.     pw1Entry = newtEntry(21, 7, "", 24, &pw1, NEWT_ENTRY_HIDDEN);
  389.     pw2Entry = newtEntry(21, 8, "", 24, &pw2, NEWT_ENTRY_HIDDEN);
  390.  
  391.     newtFormAddComponents(form, text, pw1Entry, pw2Entry, NULL);
  392.  
  393.     newtFormAddComponent(form, newtButton(20, 10, "Ok"));
  394.  
  395.     do {
  396.     newtFormSetCurrent(form, pw1Entry);
  397.     newtRunForm(form);
  398.     
  399.     if (testing) {
  400.         done = 1;
  401.     } else if (strcmp(pw1, pw2)) {
  402.         winMessage(40, 11, 30, 9, "Password Mismatch",
  403.             "The passwords you entered were different. Please "
  404.             "try again.");
  405.         newtEntrySet(pw1Entry, "", 0);
  406.         newtEntrySet(pw2Entry, "", 0);
  407.     } else if (strlen(pw1) < 6)  {
  408.         winMessage(40, 10, 30, 9, "Password Mismatch",
  409.             "The root password must be at least 6 characters "
  410.             "long.");
  411.         newtEntrySet(pw1Entry, "", 0);
  412.         newtEntrySet(pw2Entry, "", 0);
  413.     } else
  414.         done = 1;
  415.     } while (!done);
  416.  
  417.     newtPopWindow();
  418.  
  419.     if (testing) return 0;
  420.  
  421.     gettimeofday(&time2, NULL);
  422.  
  423.     salt[0] = mksalt(time1.tv_usec);
  424.     salt[1] = mksalt(time2.tv_usec);
  425.     salt[2] = '\0';
  426.  
  427.     pw = crypt(pw1, salt);
  428.  
  429.     sprintf(cmd, "/mnt/bin/sed 's&root::&root:%s:&' < /mnt/etc/passwd > "
  430.         "/mnt/etc/passwd.new", pw);
  431.  
  432.     newtFormDestroy(form);
  433.  
  434.     system(cmd);
  435.     unlink("/mnt/etc/passwd");
  436.     rename("/mnt/etc/passwd.new", "/mnt/etc/passwd");
  437.  
  438.     return 0;
  439. }
  440.     
  441. static int configureTimezone(struct installState * state) {
  442.     return timeConfig();
  443. }
  444.  
  445. static int setupBootloader(struct installState * state) {
  446.     static int first = 1;
  447. #ifdef __alpha
  448.     int rc;
  449. #else
  450.     int rc;
  451.     int append = 0;
  452.     char * version;
  453.     int i;
  454. #endif
  455.  
  456.     if (!state->isUpgrade && first) {
  457.     writeFstab(&state->fstab);
  458.     setupSerialConsole();
  459.     }
  460.  
  461.     #ifdef __alpha__
  462.     if (first) {
  463.         first = 0;
  464.         rc = kernelCopy(state->kernel);
  465.         if (rc) return rc;
  466.     }
  467.  
  468.     return INST_NOP;
  469.     #else
  470.     first = 0;
  471.  
  472.     if (state->isUpgrade && !access("/mnt/etc/conf.modules", X_OK)) {
  473.         rc = readModuleConfPersist("/mnt/etc", state->dl);
  474.         if (rc) return rc;
  475.         append = 1;
  476.     }
  477.  
  478.     writeModuleConf("/mnt/etc", state->dl, 1);
  479.  
  480.     for (i = 0; i < state->ps.numPackages; i++) {
  481.         if (!strncmp(state->ps.packages[i]->name, "kernel", 6)) break;
  482.     }
  483.  
  484.     if (i == state->ps.numPackages) {
  485.         errorWindow("I couldn't find a kernel!");
  486.         return INST_ERROR;
  487.     } 
  488.  
  489.     headerGetEntry(state->ps.packages[i]->h, RPMTAG_VERSION, NULL, 
  490.                (void *) &version, NULL);
  491.  
  492.     logMessage("installed kernel version %s", version);
  493.  
  494.     /* installLilo installs silo on the SPARC */
  495.     return installLilo("/mnt/etc", state->table, state->fstab, version);
  496.     #endif
  497. }
  498.  
  499. static int finishNetworking(struct installState * state) {
  500.     int rc;
  501.  
  502.     rc = checkNetConfig(&state->intf, &state->netc, &state->dl);
  503.     if (rc) return rc;
  504.  
  505.     writeNetConfig("/mnt/etc/sysconfig", &state->netc, &state->intf, 0);
  506.     writeNetInterfaceConfig("/mnt/etc/sysconfig/network-scripts", &state->intf);
  507.     writeResolvConf("/mnt/etc", &state->netc);
  508.     writeHosts("/mnt/etc", &state->netc, &state->intf);
  509.  
  510.     return 0;
  511. }
  512.  
  513. static int selectPath(struct installState * state) {
  514.     newtComponent install, upgrade, text, f, answer;
  515.  
  516.     memset(state, 0, sizeof(state));
  517.  
  518.     newtOpenWindow(15, 6, 50, 10, "Installation Path");
  519.  
  520.     text = newtTextbox(1, 1, 47, 3, NEWT_TEXTBOX_WRAP);
  521.     newtTextboxSetText(text,
  522.     "Would you like to install a new system or upgrade a system which "
  523.     "already contains Red Hat 2.0 or later?");
  524.    
  525.     install = newtButton(10, 6, "Install");
  526.     upgrade = newtButton(30, 6, "Upgrade");
  527.     
  528.     f = newtForm(NULL, NULL, 0);
  529.     newtFormAddComponents(f, text, install, upgrade, NULL);
  530.  
  531.     answer = newtRunForm(f);
  532.     if (answer == f)
  533.     answer = newtFormGetCurrent(f);
  534.  
  535.     newtFormDestroy(f);
  536.     newtPopWindow();
  537.  
  538.     if (answer == upgrade) {
  539.     state->steps = upgradeSteps;
  540.     state->isUpgrade = 1;
  541.     } else
  542.     state->steps = installSteps;
  543.  
  544.     return 0;
  545. }
  546.  
  547. static int upgrFindInstall(struct installState * state) {
  548.     int rc;
  549.  
  550.     /* this also turns on swap for us */
  551.     rc = readMountTable(state->table, &state->fstab);
  552.     if (rc) return rc;
  553.  
  554.     if (!testing) {
  555.     mountFilesystems(&state->fstab);
  556.  
  557.     if (state->method->prepareMedia) {
  558.         rc = state->method->prepareMedia(state->method, &state->fstab);
  559.         if (rc) {
  560.         umountFilesystems(&state->fstab);
  561.         return rc;
  562.         }
  563.     }
  564.     }
  565.  
  566.     return 0;
  567. }
  568.  
  569. static int upgrChoosePackages(struct installState * state) {
  570.     int firstTime = 1;
  571.     char * upgradeList, * rpmconvertbin;
  572.     int rc;
  573.     char * path;
  574.     char * argv[] = { NULL, NULL };
  575.  
  576.     if (testing)
  577.     path = "/";
  578.     else
  579.     path = "/mnt";
  580.  
  581.     if (firstTime) {
  582.     if (access("/mnt/var/lib/rpm/packages.rpm", R_OK)) {
  583.         if (access("/mnt/var/lib/rpm/packages", R_OK)) {
  584.         errorWindow("No RPM database exists!");
  585.         return INST_ERROR;
  586.         }
  587.  
  588.         if (state->method->getFile(state->method, "rpmconvert", 
  589.             &rpmconvertbin, 1)) {
  590.         return INST_ERROR;
  591.         }
  592.     
  593.         symlink("/mnt/var", "/var");
  594.         winStatus(35, 3, "Upgrade", "Converting RPM database...");
  595.         chmod(rpmconvertbin, 0755);
  596.         argv[0] = rpmconvertbin;
  597.         rc = runProgram(RUN_LOG, rpmconvertbin, argv);
  598.         if (state->method->rmFiles)
  599.         unlink(rpmconvertbin);
  600.  
  601.         newtPopWindow();
  602.         if (rc) return INST_ERROR;
  603.     }
  604.     
  605.     winStatus(35, 3, "Upgrade", "Finding packages to upgrade...");
  606.     if (state->method->getFile(state->method, "uglist", &upgradeList, 1))
  607.         return INST_ERROR;
  608.     rc = ugFindUpgradePackages(&state->ps, path, upgradeList);
  609.     if (state->method->rmFiles)
  610.         unlink(upgradeList);
  611.     newtPopWindow();
  612.     if (rc) return rc;
  613.     firstTime = 0;
  614.     psVerifyDependencies(&state->ps, 1);
  615.     }
  616.  
  617.     return psSelectPackages(&state->ps, &state->cs, 0, 1);
  618. }
  619.  
  620. #define DO_RETRY    1
  621. #define DO_NEXT        2
  622. #define DO_PREV        3
  623. #define DO_MENU        4
  624.  
  625. static int errcanChoices(char * name, int wasCancelled) {
  626.     newtComponent form, retry, previous, menu, text, exitb, answer;
  627.     char textBuf[1000];
  628.  
  629.     if (wasCancelled) {
  630.     sprintf(textBuf, "You cancelled step \"%s\".\n\n", name);
  631.     newtOpenWindow(15, 3, 50, 16, "Cancelled");
  632.     } else {
  633.     sprintf(textBuf, "An error occured during step \"%s\" of the "
  634.         "install.\n\n", name);
  635.     newtOpenWindow(15, 3, 50, 16, "Error");
  636.     }
  637.  
  638.     form = newtForm(NULL, NULL, 0);
  639.  
  640.     strcat(textBuf, "You may retry that step, return to the previous step "
  641.             "in the install, or see a menu of installation steps "
  642.             "which will allow you to move around in the install "
  643.             "more freely. It is not recommended to use the menu "
  644.             "unless you are already familiar with Red Hat Linux. "
  645.             "What would you like to do?");
  646.  
  647.     text = newtTextbox(1, 1, 48, 10, NEWT_TEXTBOX_WRAP);
  648.     newtTextboxSetText(text, textBuf);
  649.   
  650.     if (testing) {
  651.     previous = newtButton(1, 12, "Previous");
  652.     retry = newtButton(15, 12, "Retry");
  653.     menu = newtButton(28, 12, "Menu");
  654.     exitb = newtButton(39, 12, "Exit");
  655.     newtFormAddComponents(form, text, previous, retry, menu, exitb, NULL);
  656.     } else {
  657.     previous = newtButton(5, 12, "Previous");
  658.     retry = newtButton(20, 12, "Retry");
  659.     menu = newtButton(38, 12, "Menu");
  660.     newtFormAddComponents(form, text, previous, retry, menu, NULL);
  661.     }
  662.  
  663.     answer = newtRunForm(form);
  664.  
  665.     newtPopWindow();
  666.     newtFormDestroy(form);
  667.  
  668.     if (answer == previous)
  669.     return DO_PREV;
  670.     else if (answer == retry)
  671.     return DO_RETRY;
  672.     else if (answer == menu)
  673.     return DO_MENU;
  674.  
  675.     newtFinished();
  676.     exit(0); 
  677. }
  678.  
  679. static int stepMenu(struct installState * state, int currStep) {
  680.     newtComponent form, listbox, okay, text;
  681.     int firstStep = currStep;
  682.     long i;
  683.     int numChoices, listHeight;
  684.     char buf[200];
  685.  
  686.     newtOpenWindow(15, 3, 50, 16, "Installation Steps");
  687.  
  688.     while (state->steps[firstStep].prev != -1)
  689.     firstStep = state->steps[firstStep].prev;
  690.  
  691.     form = newtForm(NULL, NULL, 0);
  692.  
  693.     i = firstStep, numChoices = 0;
  694.     do {
  695.     numChoices++;
  696.     i = state->steps[i].next;
  697.     } while (state->steps[i].prev != -1 && state->steps[i].next != STEP_DONE);
  698.     numChoices++;
  699.  
  700.     if (numChoices > 6)
  701.     listHeight = 6;
  702.     else
  703.     listHeight = 0;
  704.  
  705.     listbox = newtListbox(10, 4, listHeight, NEWT_LISTBOX_RETURNEXIT);
  706.  
  707.     text = newtTextbox(1, 1, 48, 3, NEWT_TEXTBOX_WRAP);
  708.     newtTextboxSetText(text, 
  709.         "What step would you like to run? Steps with a * next "
  710.         "to them have already been completed.");
  711.  
  712.     newtListboxAddEntry(listbox, "  Continue with install", 
  713.             (void *) STEP_DONE + 1);
  714.     for (i = firstStep; i < (firstStep + numChoices); i++) {
  715.     if (state->steps[i].completed)
  716.        strcpy(buf, "* ");
  717.     else
  718.        strcpy(buf, "  ");
  719.  
  720.     strcat(buf, state->steps[i].name);
  721.     newtListboxAddEntry(listbox, buf, (void *) i);
  722.     }
  723.  
  724.     okay = newtButton(23, 11, "Ok");
  725.     newtFormAddComponents(form, text, listbox, okay, NULL);
  726.  
  727.     newtRunForm(form);
  728.  
  729.     i = (long) newtListboxGetCurrent(listbox);
  730.  
  731.     newtFormDestroy(form);
  732.     newtPopWindow();
  733.  
  734.     if (i == STEP_DONE + 1)
  735.     return -1;
  736.  
  737.     return i;
  738. }
  739.  
  740. static int getNextStep(struct installState * state, int lastStep, int lastrc) {
  741.     int choice;
  742.     int nextStep;
  743.  
  744.     if (state->lastChoice == DO_MENU)
  745.     choice = DO_MENU;
  746.     else if (lastrc == INST_ERROR) {
  747.     choice = errcanChoices(state->steps[lastStep].name, 0);
  748.     } else if (lastrc == INST_CANCEL) {
  749.     choice = errcanChoices(state->steps[lastStep].name, 1);
  750.     } else if (lastrc == INST_NOP) {
  751.     choice = state->lastChoice;
  752.     } else {
  753.     choice = DO_NEXT;
  754.     }
  755.  
  756.     switch (choice) {
  757.       case DO_PREV:
  758.     nextStep = state->steps[lastStep].prev;
  759.     while (nextStep != -1 && state->steps[nextStep].skipOnCancel && 
  760.            state->steps[nextStep].prev != -1)
  761.         nextStep = state->steps[nextStep].prev;
  762.  
  763.     if (nextStep == -1 || nextStep == lastStep) {
  764.         messageWindow("Cancelled", "I can't go to the previous step"
  765.               " from here. You will have to try again.");
  766.         nextStep = lastStep;
  767.     }
  768.     break;
  769.  
  770.       case DO_RETRY:
  771.     nextStep = lastStep;
  772.     break;
  773.  
  774.       case DO_MENU:
  775.     nextStep = stepMenu(state, lastStep);
  776.     if (nextStep == -1) {
  777.         choice = DO_NEXT;
  778.  
  779.         if (lastrc)
  780.         nextStep = lastStep;
  781.         else
  782.         nextStep = state->steps[lastStep].next;
  783.     }
  784.     break;
  785.  
  786.       case DO_NEXT: default:
  787.         nextStep = state->steps[lastStep].next;
  788.     break;
  789.     }
  790.  
  791.     state->lastChoice = choice;
  792.  
  793.     return nextStep;
  794. }
  795.  
  796. void doSuspend(void) {
  797.     pid_t pid;
  798.     int status;
  799.  
  800.     newtSuspend();
  801.     if (!(pid = fork())) {
  802.     printf("\n\nType <exit> to return to the install program.\n\n");
  803.     execl("/bin/sh", "-/bin/sh", NULL);
  804.     perror("error execing /bin/sh");
  805.     sleep(5);
  806.     exit(1);
  807.     }
  808.     waitpid(pid, &status, 0);
  809.     newtResume();
  810. }
  811.  
  812. static void setupSerialConsole(void) {
  813.     int first = 1;
  814.     struct stat sb;
  815.     char * argv[10] = { "/usr/sbin/setconsole", "--speed", NULL, NULL, NULL };
  816.     struct termios tos;
  817.     speed_t speed;
  818.  
  819.     if (!first) return;
  820.     first = 0;
  821.  
  822.     if (fstat(0, &sb)) {
  823.     logMessage("error stat'ing stdin: %s", strerror(errno));
  824.     return;
  825.     }
  826.  
  827.     if (!S_ISCHR(sb.st_mode)) {
  828.     logMessage("stdin isn't a character device!!! ack!");
  829.     return;
  830.     }
  831.  
  832.     if (major(sb.st_rdev) != 4) {
  833.     if (minor(sb.st_rdev) == 64)
  834.         argv[3] = "ttya";
  835.     else
  836.         argv[3] = "ttyb";
  837.  
  838.         tcgetattr(0, &tos);
  839.     speed = cfgetospeed(&tos);
  840.     switch (speed) {
  841.         case B38400:    argv[2] = "38400"; break;
  842.         case B19200:    argv[2] = "19200"; break;
  843.         default:        argv[2] = "9600";  break;
  844.     }
  845.  
  846.     if (access("/mnt/usr/sbin/setconsole", X_OK)) {
  847.         logMessage("/mnt/usr/sbin/setconsole does not exist -- skipping");
  848.         return;
  849.     }
  850.  
  851.     logMessage("setting up %s as serial console, speed is %s", argv[3], 
  852.             argv[2]);
  853.     runProgramRoot(RUN_LOG, "/mnt", "/usr/sbin/setconsole", argv);
  854.     }
  855. }
  856.  
  857. static int configurePrinter(struct installState * state) {
  858.     if (testing) {
  859.     return doConfigurePrinters("/");
  860.     } else if (!access("/mnt/usr/bin/lpr", X_OK)) {
  861.     return doConfigurePrinters("/mnt");
  862.     }
  863.  
  864.     return INST_NOP;
  865. }
  866.  
  867. int main(int argc, char ** argv) {
  868.     char ** argptr;
  869.     int step = STEP_FIRST;
  870.     int rc = 0;
  871.     struct installState state;
  872.     int i;
  873.     int isForce = 0;
  874.     int len = strlen(argv[0]);
  875.     char * spaces;
  876.     int isRescue = 0;
  877.     DIR * dir;
  878.     struct dirent * ent;
  879.  
  880.     spaces = strdup("                                                      ");
  881.  
  882.     if (!strcmp(argv[0] + len - 6, "umount")) {
  883.     return umountCommand(argc, argv);
  884.     } else if (!strcmp(argv[0] + len - 5, "mount")) {
  885.     return mountCommand(argc, argv);
  886.     } else if (!strcmp(argv[0] + len - 5, "mkdir")) {
  887.     return mkdirCommand(argc, argv);
  888.     } else if (!strcmp(argv[0] + len - 5, "mknod")) {
  889.     return mknodCommand(argc, argv);
  890.     } else if (!strcmp(argv[0] + len - 3, "cat")) {
  891.     return catCommand(argc, argv);
  892.     } else if (!strcmp(argv[0] + len - 2, "rm")) {
  893.     return rmCommand(argc, argv);
  894.     } else if (!strcmp(argv[0] + len - 5, "chmod")) {
  895.     return chmodCommand(argc, argv);
  896.     } else if (!strcmp(argv[0] + len - 5, "lsmod")) {
  897.     return lsmodCommand(argc, argv);
  898.     } else if (!strcmp(argv[0] + len - 6, "mkswap")) {
  899.     return mkswapCommand(argc, argv);
  900.     } else if (!strcmp(argv[0] + len - 6, "swapon")) {
  901.     return swaponCommand(argc, argv);
  902.     }
  903.  
  904.     /* if this fails, it's okay -- it might help with free space though */
  905.     unlink("/sbin/install");
  906.  
  907.     newtSetSuspendCallback(doSuspend);
  908.  
  909.     memset(&state, 0, sizeof(state));
  910.     state.steps = installSteps;            /* blind guess */
  911.  
  912.     argptr = argv + 1;
  913.     while (*argptr) {
  914.     if (!strcmp(*argptr, "--method")) {
  915.         argptr++;
  916.         if (!*argptr) {
  917.         fprintf(stderr, "--method requires argument\n");
  918.         exit(1);
  919.         }
  920.         state.method = findInstallMethod(*argptr);
  921.         if (!state.method) {
  922.         fprintf(stderr, "unknown install method: %s\n", *argptr);
  923.         exit(1);
  924.         }
  925.     } else if (!strcmp(*argptr, "--force")) {
  926.         isForce = 1;
  927.     } else if (!strcmp(*argptr, "--rescue")) {
  928.         isRescue = 1;
  929.     } else if (!strcmp(*argptr, "--test")) {
  930.         testing = 1;
  931.     } else if (!strcmp(*argptr, "--pcmcia")) {
  932.         argptr++;
  933.         if (!*argptr) {
  934.         fprintf(stderr, "--pcmcia requires argument\n");
  935.         exit(1);
  936.         }
  937.         state.pcmcia = *argptr;
  938.     } else if (!strcmp(*argptr, "--kernel")) {
  939.         argptr++;
  940.         if (!*argptr) {
  941.         fprintf(stderr, "--kernel requires argument\n");
  942.         exit(1);
  943.         }
  944.         state.kernel = *argptr;
  945.     } else {
  946.         /* skipping unknown arguments allows for future expansion */
  947.         fprintf(stderr, "unknown argument: %s\n", *argptr);
  948.     }
  949.     argptr++;
  950.     }
  951.  
  952.     if (!isRescue && !state.method) {
  953.     fprintf(stderr, "--method argument is required\n");
  954.     exit(1);
  955.     }
  956.  
  957.     if (!testing && !isForce && (getpid() > 50)) {
  958.     fprintf(stderr, "you're running me on a live system! that's ");
  959.     fprintf(stderr, "incredibly stupid.\n");
  960.     exit(1);
  961.     }
  962.  
  963.     fprintf(stderr, "in second stage install\n");
  964.     
  965.     openLog();
  966.  
  967.     logMessage("second stage install running (version " VERSION " built "
  968.         __DATE__ " " __TIME__ ")");
  969.  
  970.     spawnShell();
  971.  
  972.     newtInit();
  973.     newtCls();
  974.  
  975.     newtDrawRootText(0, 0, "Red Hat Linux (C) 1997 Red Hat Software");
  976.     newtPushHelpLine(NULL);
  977.  
  978.     if (isRescue) {
  979.     do {
  980.         rc = setupSCSIInterfaces(0, &state.dl);
  981.     } while (rc);
  982.  
  983.     /* cut! we're out of here */
  984.  
  985.     newtFinished();
  986.  
  987.     execl("/bin/sh", "-/bin/sh", NULL);
  988.     fprintf(stderr, "ack! I couldn't manage to execl() /bin/sh: %s",
  989.             strerror(errno));
  990.     while (1);
  991.     }
  992.  
  993.     readNetConfig("/tmp", &state.netc);
  994.  
  995.     #ifndef __sparc__ 
  996.     readKbdConfig("/tmp", &state.keyboard);
  997.     #endif
  998.  
  999.     dir = opendir("/tmp");
  1000.     if (!dir) 
  1001.     logMessage("failed to open directory /tmp: %s", strerror(errno));
  1002.     else {
  1003.     errno = 0;
  1004.     while ((ent = readdir(dir))) {
  1005.         if (!strncmp("ifcfg-", ent->d_name, 6)) break;
  1006.     }
  1007.  
  1008.     if (!ent && errno) {
  1009.         logMessage("error reading directory entry: %s", strerror(errno));
  1010.     } else if (ent) {
  1011.         logMessage("found network config file %s", ent->d_name);
  1012.         readNetInterfaceConfig("/tmp", ent->d_name + 6, &state.intf);
  1013.     }
  1014.     }
  1015.     closedir(dir);
  1016.  
  1017.     readModuleConf("/tmp", &state.dl);
  1018.  
  1019.     /* make sure we don't pick up any gunk from the outside world */
  1020.     putenv("PATH=/usr/bin:/bin:/sbin:/usr/sbin");
  1021.     putenv("LD_LIBRARY_PATH=");
  1022.  
  1023.     while (step != STEP_DONE) {
  1024.     i = strlen(state.steps[step].name);
  1025.     newtDrawRootText(0, 0 - i, state.steps[step].name);
  1026.     newtRefresh();
  1027.     rc = state.steps[step].fn(&state);
  1028.     if (!rc)
  1029.         state.steps[step].completed = 1;
  1030.  
  1031.     spaces[i] = '\0';
  1032.     newtDrawRootText(0, 0 - i, spaces);
  1033.     spaces[i] = ' ';
  1034.  
  1035.     step = getNextStep(&state, step, rc);
  1036.     }
  1037.  
  1038.     newtDrawRootText(0, 72, "Complete");
  1039.     winMessage(10, 3, 60, 16, "Done", 
  1040.     "Congratulations, installation is complete.\n\n"
  1041.     "Remove the floppy from the drive and "
  1042.     "press return to reboot. For information on fixes which are "
  1043.     "available for this release of Red Hat Linux, consult the "
  1044.     "Errata available from http://www.redhat.com.\n\n"
  1045.     "Information on configuring your system is available in the post "
  1046.     "install chapter of the Official Red Hat Linux User's Guide.");
  1047.  
  1048.     umountFilesystems(&state.fstab);
  1049.  
  1050.     newtFinished();
  1051.  
  1052.     return 0;
  1053. }
  1054.